//Documentation complete
/**
 * @author Alex
 * @version 2009MR30
 */

package problemDomain;

import java.text.DecimalFormat;
import static java.util.logging.Level.*;
import static utilities.XMLTools.encodeEntities;

import java.util.logging.*;

/**
 * An error which occurs in the system.
 */
public class ErrorBean extends Throwable implements Bean {
	
	/* Constants */
	
	private static final long serialVersionUID = -8700867442856242466L;
	
	/* END Constants */
	
	
	/* Enumerators */

	/**
	 * An error code in the system.
	 */
	public static enum ErrorCode {
		
		/* Enumeration Codes */
		
		/*
		 * An error code is 6 digits long.
		 * 
		 * 		Syntax: 
		 * 			OOAAEE as [object][attribute][error]  
		 * 
		 * 		Database related errors can be described:
		 * 			TTAAEE as [table][attribute][error series]
		 */
		
		
		/* Null Code */
		NULL										(     1, "<null ErrorCode>",							null),
		
		
		
		/* No Errors */
		NO_ERRORS									(     0, "No errors.",									null),
		
		
		
		/* Presentation Level Errors																			01.00.00 */
		SEARCH_RESULTS_EMPTY						( 10101, "No results found.",							INFO),
		
		ITEM_LIST_EMPTY								( 10201, "No menu items.",								INFO),
		
		ITEMTYPE_LIST_EMPTY							( 10301, "No item types.",								INFO),
		
		LIST_EMPTY									( 10401, "No items.",									INFO),
		
		
		
		/* Employee Errors																						02.00.00 */
		EMPLOYEE_ID_INVALID							( 20101, "Invalid Employee ID.",						INFO),
		
		EMPLOYEE_INCORRECT_USERNAME_OR_PASSWORD		( 20201, "Invalid Username or Password.",				INFO),
		EMPLOYEE_PRIVILEGES_NOT_SPECIFIED			( 20202, "Employee priveleges are not specified.",		INFO),
		EMPLOYEE_INCORRECT_PASSCODE					( 20203, "Invalid Passcode.",							INFO),
		
		EMPLOYEE_USERNAME_DUPLICATE					( 20301, "Username already exists.",					INFO),
		EMPLOYEE_USERNAME_INVALID					( 20302, "Username does not exist.",					INFO),
		EMPLOYEE_USERNAME_TOO_LONG					( 20303, "Employee username too long.",					INFO),
		
		EMPLOYEE_PASSWORD_TOO_LONG					( 20401, "Employee password too long.",					INFO),
		EMPLOYEE_PASSWORD_TOO_SHORT					( 20402, "Employee password too short.",				INFO),
		
		EMPLOYEE_PASS_CODE_INVALID					( 20501, "Invalid Employee pass code.",					INFO),
		
		EMPLOYEE_FIRST_NAME_INVALID					( 20601, "Invalid first name.",							INFO),
		
		EMPLOYEE_LAST_NAME_INVALID					( 20701, "Invalid first name.",							INFO),
		
		
		
		/* Item Errors																							03.00.00 */
		ITEM_NAME_TOO_LONG							( 30101, "Item name is too long.",						INFO),
		
		ITEM_DESCRIPTION_TOO_LONG					( 30201, "Item description is too long.",				INFO),
		
		ITEM_PRICE_INVALID							( 30301, "Invalid Item price.",							INFO),
		ITEM_PRICE_NULL								( 30302, "Item price value is null.",					INFO),
		
		ITEM_COST_INVALID							( 30401, "Invalid Item cost.",							INFO),
		ITEM_COST_NULL								( 30402, "Item cost value is null.",					INFO),
		
		ITEM_ID_INVALID								( 30501, "Invalid Item ID.",							INFO),
		ITEM_ID_NULL								( 30502, "Invalid Item ID.",							INFO),
		
		ITEM_NUMBER_INVALID							( 30601, "Invalid Item number.",						INFO),
		ITEM_NUMBER_NULL							( 30602, "Invalid Item number.",						INFO),
		
		ITEM_TYPE_INVALID							( 30701, "Invalid Item type.",							INFO),
		
		ITEM_AVAILABILITY_INVALID					( 30801, "Invalid Item Availability.",					INFO),
		ITEM_AVAILABILITY_NULL						( 30802, "Availability value is null.",					INFO),
		
		
		
		/* Item Type Errors																						04.00.00 */
		ITEMTYPE_ID_INVALID							( 40101, "Invalid Item Type ID.",						INFO),
		
		ITEMTYPE_NAME_INVALID						( 40201, "Invalid Item Type name.",						INFO),
		
		ITEMTYPE_DESCRIPTION_INVALID				( 40301, "Item Type description is too long.",			INFO),
		
		
		
		/* Broker Errors																						05.00.00 */
		BROKER_CONNECTION_NOT_AVAILABLE				( 50101, "Database connection unavailable.",			SEVERE),
		BROKER_PREPARED_STATEMENTS_NOT_AVAILABLE	( 50102, "Unable to prepare statements.",				SEVERE),
		
		BROKER_INSERT_ERROR							( 50104, "Error inserting data.",						SEVERE),
		BROKER_UPDATE_ERROR							( 50105, "Error updating data.",						SEVERE),
		BROKER_DELETE_ERROR							( 50106, "Error deleting data.",						SEVERE),
		BROKER_SELECT_ERROR							( 50107, "Error selecting data.",						SEVERE),
		
		BROKER_UNABLE_TO_CLOSE_CONNECTION			( 50110, "Unable to close the connection.",				SEVERE),
		BROKER_CONFIGFILE_NOTFOUND					( 50111, "Configuration file not found",				SEVERE),
		
		
		
		/* Menu Errors																							06.00.00 */
		MENU_ID_INVALID								( 60101, "Invalid Menu ID.",							INFO),
		
		MENU_NAME_TOO_LONG							( 60201, "Menu name is too long.",						INFO),
		
		MENU_DESCRIPTION_INVALID					( 60301, "Menu description is too long.",				INFO),
		MENU_ACTIVE_NULL							( 60302, "Menu active status is null.",					INFO),
		
		MENUITEM_LIST_NULL							( 60401, "Menu item's list is null.",					INFO),
		
		MENUITEM_ACTIVE_NULL						( 60501, "Menu item's active is null.",					INFO),
		
		MENUITEM_PRICE_INVALID						( 60601, "Menu item's price is invalid.",				INFO),
		
		MENUITEM_NUMBER_INVALID						( 60701, "Menu item's number is invalid.",				INFO),
		
		MENUITEM_ID_INVALID							( 60801, "Menu item's ID number is invalid.",			INFO),
		
		MENUITEM_NAME_INVALID						( 60901, "Menu item's name is invalid.",				INFO),
		
		MENUITEM_MENU_NULL							( 61001, "Menu item's menu is null",					INFO),
		
		
		/* OrderItem Errors																						07.00.00 */
		ORDERITEM_INVALID							( 70101, "Invalid Order Item.",							INFO),
		
		ORDERITEM_QUANTITY_INVALID					( 70201, "Invalid Order Item quantity.",				INFO),
		
		
		
		/* Patron Errors																						08.00.00 */
		PATRON_ID_INVALID							( 80101, "Invalid Patron ID.",							INFO),
		
		PATRON_USERNAME_DUPLICATE					( 80201, "Username already exists.",					INFO),
		PATRON_USERNAME_INVALID						( 80202, "Username does not exist.",					INFO),
		PATRON_USERNAME_TOO_LONG					( 80203, "Patron username too long.",					INFO),
		
		PATRON_PASSWORD_TOO_LONG					( 80301, "Patron password too long.",					INFO),
		PATRON_PASSWORD_TOO_SHORT					( 80302, "Patron password too short.",					INFO),
		
		PATRON_FIRST_NAME_INVALID					( 80401, "Invalid first name.",							INFO),
		
		PATRON_LAST_NAME_INVALID					( 80501, "Invalid first name.",							INFO),
		
		PATRON_EMAIL_INVALID						( 80601, "Patron email too long.",						INFO),
		
		PATRON_STREET_INVALID						( 80701, "Patron street too long.",						INFO),
		
		PATRON_CITY_INVALID							( 80801, "Patron city too long.",						INFO),
		
		PATRON_PROVINCE_INVALID						( 80901, "Invalid Patron province.",					INFO),
		
		PATRON_POSTAL_CODE_INVALID					( 81001, "Invalid Patron postal code.",					INFO),
		
		PATRON_PHONE_NUMBER_INVALID					( 81101, "Invalid Patron phone number.",				INFO),
		
		PATRON_DATE_ENTERED_INVALID					( 81201, "Invalid Patron date entered.",				INFO),
		
		PATRON_ACTIVE_STATUS_INVALID				( 81301, "Invalid Patron status.",						INFO),
		
		PATRON_INCORRECT_USERNAME_OR_PASSWORD		( 81401, "Invalid Username or Password.",				INFO),
		
		//PATRON_INVALID_PASSWORD						( 81501, "Invalid Password.",							INFO),
		
		
		/* Payment Errors 																						09.00.00 */
		PAYMENT_AMOUNT_INVALID						( 90101, "Invalid Payment Amount.",						INFO),
		
		PAYMENT_DATE_NULL							( 90201, "Invalid Payment Date Paid Amount.",			INFO),

		PAYMENT_ID_INVALID							( 90301, "Invalid Payment ID.",							INFO),
		
		PAYMENT_STATUS_INVALID						( 90401, "Invalid Payment Status.",						INFO),
		
		PAYMENT_PAYMENT_METHOD_INVALID				( 90501, "Invalid Payment type.",						INFO),
		
		
		/* Delivery Errors																						10.00.00 */
		DELIVERY_ID_INVALID							(100101, "Invalid delivery ID.",						INFO),
		
		DELIVERY_ADDRESS_TOO_LONG					(100201, "Street of delivery address too long.",		INFO),
		
		DELIVERY_CITY_TOO_LONG						(100301, "City of delivery address too long.",			INFO),
		
		DELIVERY_PROVINCE_TOO_LONG					(100401, "Province of delivery address too long.",		INFO),
		
		DELIVERY_POSTAL_CODE_INVALID				(100501, "Postal code of delivery address invalid.",	INFO),
		
		DELIVERY_ROOM_NUMBER_TOO_LONG				(100601, "Room number of delivery address too long.",	INFO),
		
		DELIVERY_BUILDING_NAME_TOO_LONG				(100701, "Building name of delivery address too long.",	INFO),

		DELIVERY_FIRSTNAME_TOO_LONG					(100801, "Receiver's first name is too long.",			INFO),
		
		DELIVERY_LASTNAME_TOO_LONG					(100901, "Receiver's last name is too long.",			INFO),
		
		DELIVERY_INSTRUCTION_TOO_LONG				(101001, "Delivery instruction name is too long.",		INFO),
		
		
		/* Credit Card Errors																					11.00.00 */
		CREDITCARD_TYPE_INVALID						(110101, "Invalid Payment Card Type.",					INFO),
		
		CREDITCARD_NUMBER_INVALID					(110201, "Invalid Payment Card Number.",				INFO),
		
		CREDITCARD_EXPIRY_MONTH_INVALID				(110301, "Invalid Payment Expiry Month.",				INFO),
		
		CREDITCARD_EXPIRY_YEAR_INVALID				(110401, "Invalid Payment Expiry Year.",				INFO),
		
		
		/* Order Errors																							12.00.00 */
		ORDER_ID_INVALID							(120101, "Invalid Order ID.",							INFO),
		
		ORDER_DATEPLACED_INVALID					(120201, "Invalid Order Date Placed.",					INFO),
		
		ORDER_GSTAMOUNT_INVALID						(120301, "Invalid Order Gst Amount.",					INFO),
		
		ORDER_PSTAMOUNT_INVALID						(120401, "Invalid Order Pst Amount.",					INFO),
		
		ORDER_BALANCEPAID_INVALID					(120501, "Invalid Order Balance Paid.",					INFO),
		
		ORDER_STATUS_INVALID						(120601, "Invalid Order Status.",						INFO),
		
		ORDER_FINALIZED								(120601, "Order has been finalized and can't be updated",   INFO),
		
		ORDER_PAYMENTSTATUS_INVALID					(120701, "Invalid Order Payment Status.",				INFO),
		
		
		
		
		
		/* Reservation Errors																					13.00.00 */
		RESERVATION_ID_INVALID						(130101, "Invalid Reservation ID.",						INFO),
		
		RESERVATION_FIRSTNAME_INVALID				(130201,"Invalid Reservation First Name.",				INFO),
		
		RESERVATION_LASTNAME_INVALID				(130301,"Invalid Reservation Last Name.",				INFO),
		
		RESERVATION_PHONE_INVALID					(130401,"Invalid Reservation Phone.",					INFO),
		
		RESERVATION_NUMBEROFPEOPLE_INVALID			(130501,"Invalid Reservation Number of People.",		INFO),
		
		RESERVATION_DATEPLACED_INVALID				(130601,"Invalid Reservation Date Placed.",				INFO),
		
		RESERVATION_DATERESERVED_INVALID			(130701,"Invalid Reservation Date reserved.",			INFO),
		
		RESERVATION_DESCRIPTION_INVALID				(130801,"Invalid Reservation Description.",				INFO),
		
		RESERVATION_CREATEDBY_INVALID				(130901,"Invalid Reservation Created By.",				INFO),
		
		RESERVATION_PATRON_INVALID					(131001,"Invalid Reservation Patron.",					INFO),
		
		
		
		/* OrderItem Errors																						14.00.00 */
		FOODITEM_LIST_INVALID						(140101, "Invalid Food Item list.",						INFO),
		
		FOODITEM_ID_INVALID							(140201, "Invalid Food Item ID.",						INFO),
		
		
		
		/* SalesPerTimeReport Errors																						15.00.00 */
		REPORT_CANNOT_GENERATE_CHART				(150101, "Cannot generate chart.",						INFO),
		
		REPORT_INVALID_DATE							(150201, "Invalid date.",								INFO),
		
		REPORT_CANNOT_GENERATE_REPORT				(150301, "Cannot generate report.",						INFO),
		
		REPORT_INVALID_REPORTLIST					(150401, "SalesPerTimeReport list is invalid.",						INFO),
		
		REPORT_INVALID_TOTAL						(150501, "SalesPerTimeReport total is invalid.",					INFO),
		
		
		/* END Enumeration Codes */
		
		;
		
		/* Static Constants */
		
		private static DecimalFormat CODE_FORMATTER = new DecimalFormat("000000");
		
		/* END Static Constants */
		
		
		/* Attributes */
		
		private String message;
		private int errorCode;
		private Level level;
		
		/* END Attributes */
		
		
		/* Constructors */
		
		private ErrorCode (int errorCode, String message, Level level) {
			this.message = message;
			this.errorCode = errorCode;
			this.level = level;
		}
		
		/* END Constructors */
		
		
		/* Accessors */
		
		/**
		 * Returns the error code number
		 * @return the error code number
		 */
		public int getCode () {
			return errorCode;
		}
		
		public String getMessage () {
			return message;
		}
		
		public Level getLevel () {
			return level;
		}
		
		/* END Accessors */
		
		
		/* (Object) Methods */
		
		@Override
		public String toString () {
			return CODE_FORMATTER.format(errorCode) + ": " + message;
		}
		
		/* END (Object) Methods */
		
	}
	
	/* END Enumerators */
	
	
	/* Constants */
	
	private final ErrorCode code;
	private final String detail;
	
	private static final String LOG_FILE = "ordrs.%u-%g.log";
	
	/* END Constants */
	
	
	/* Static Initializer */
	
	static {
		try {
			FileHandler fh = new FileHandler(LOG_FILE, 50000, 4, true);
			fh.setFormatter(new SimpleFormatter());
			Logger.getLogger("").addHandler(fh);
		} catch (Exception e) {}
	}
	
	/**/
	
	
	/* Constructors */
	
	/**
	 * Constructs an ErrorBean from a certain ErrorCode.
	 * @param code the ErrorCode of the ErrorBean
	 */
	public ErrorBean (ErrorCode code) {
		this(code, null);
	}

	/**
	 * Constructs an ErrorBean from a certain ErrorCode.
	 * @param code the ErrorCode of the ErrorBean
	 * @param detail a detailed error message, i.e. a parameter value, return value, etc.
	 */
	public ErrorBean (ErrorCode code, String detail) {
		this.code = code;
		this.detail = detail;
	}
	
	/* END Constructors */
	
	
	/* Accessors */
	
	/**
	 * Returns the error code number.
	 * @return the error code number
	 */
	public int getCode () {
		return code.getCode();
	}
	
	/* END Accessors */
	
	
	/* Methods */
	
	public boolean codeEquals (ErrorCode code) {		
		return this.code == code;
	}
	
	/* END Methods */
	
	
	/* (Bean) Methods */
	
	@Override
	public boolean isValid () throws ErrorBean {
		return true;
	}
	
	@Override
	public String toXML () {
		StringBuilder sb = new StringBuilder();
		sb.append("<error>");
		sb.append("<code>");
		sb.append(getCode());
		sb.append("</code>");
		sb.append("<message>");
		sb.append(code.message);
		sb.append("</message>");
		sb.append("<detail>");
		sb.append(detail != null ? detail : "");
		sb.append("</detail>");
		sb.append("</error>");
		return encodeEntities(sb.toString());
	}
	
	/* END (Bean) Methods */
	
	
	/* (Throwable) Methods */
	
	/**
	 * Returns the error message.
	 * @return the error message
	 */
	@Override
	public String getMessage () {
		return appendDetail(code.getMessage());
	}
	
	/* END (Throwable) Methods */
	
	
	/* (Object) Methods */
	
	@Override
	public String toString () {
		return appendDetail(code.toString());
	}
	
	/* END (Object) Methods */
	
	
	/* Private Methods */
	
	private String appendDetail (String message) {
		if (detail == null)
			return message;
		return message + " : " + detail;
	}
	
	/* END Private Methods */
	
	
	/* Static Methods */
	
	/**
	 * Returns an <code>ErrorBean</code> representing a success (a code showing no errors).
	 * @return a "success" <code>ErrorBean</code>
	 */
	public static ErrorBean getSuccess () {
		return getSuccess(null);
	}
	
	/**
	 * Returns an <code>ErrorBean</code> representing a success (a code showing no errors) with a detail message.
	 * @param detail the detail message
	 * @return a "success" <code>ErrorBean</code>
	 */
	public static ErrorBean getSuccess (String detail) {
		return new ErrorBean(ErrorCode.NO_ERRORS, detail);
	}
	
	public static void throwError (ErrorCode code, Object source) throws ErrorBean {
		throwError(code, null, source);
	}
	
	public static void throwError (ErrorCode code, String detail, Object source) throws ErrorBean {
		ErrorBean bean = new ErrorBean(code, detail);
		if (code != ErrorCode.NULL && code != ErrorCode.NO_ERRORS) {
			Logger logger = Logger.getLogger(source.getClass().getName());
			logger.log(code.getLevel(), bean.toString(), bean);
		}
		throw bean;
	}
	
	/* END Static Methods */
	
}
